/*
 *  AIController.cpp
 *  Pirates2011
 *
 *  Created by Alan Dorin on 10/03/11.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */
 
using namespace std;

#include "AIController.h"
#include "Sea.h"
#include "ShipBase.h"

AIController::AIController(void)
{
	shipPtr = NULL;
	seaPtr = NULL;
}

void AIController::setShipPtr(const Ship* newShipPtr)
{
	shipPtr = newShipPtr;
}

void AIController::setSeaPtr(const Sea* newSeaPtr)
{
	seaPtr = newSeaPtr;
}

AIController::~AIController(void)
{
	;	// don't delete the ship and sea! These are
		// not purely local to this object
}

// --------------------------------------
// Ship data available to the controller.

long AIController::getShipPositionX(void)
const
{
	assert(shipPtr);
	return shipPtr->getPositionX();
}

long AIController::getShipPositionY(void)
const
{
	assert(shipPtr);
	return shipPtr->getPositionY();
}

Globals::NeighbourDirection AIController::getShipAheadDirection(void)
const
{
	assert(shipPtr);
	return shipPtr->getAheadDirection();
}

long AIController::getShipVisionRange(void)
const
{
	assert(shipPtr);
	
	// Ship can see as far as the cannon fires plus 1 step.
	// This allows a ship to avoid enetering into a fight if it wants to.
	return shipPtr->getCannonRange() + 1;
}

long AIController::getShipCannonRange(void)
const
{
	assert(shipPtr);
	return shipPtr->getCannonRange();
}


bool AIController::justDamagedShip(void)
const
{
	assert(shipPtr);
	return shipPtr->justDamaged();
}

long AIController::getShipMaxDamage(void)
const
{
	assert(shipPtr);
	return shipPtr->getMaxDamage();
}

long AIController::getShipDamage(void)
const
{
	assert(shipPtr);
	return shipPtr->getDamage();
}

bool AIController::getShipLastActionSuccess(void)
const
{
	assert(shipPtr);
	return shipPtr->getRequestedActionSuccessFlag();
}

long AIController::getShipRewardStored(void)
const
{
	assert(shipPtr);
	return shipPtr->getRewardStored();
}

// --------------------------------------
// Sea data available to the controller.

bool AIController::isGoldMarkerHere(void)
const
{
	assert(seaPtr);

	return seaPtr->cellArrayIsOccupiedByGoldMarker(getShipPositionX(), getShipPositionY());
}

bool AIController::isShipAt(long relativeX, long relativeY) // relativeX & relativeY < visionRange
const
{
	assert(seaPtr);
	long visionRange = getShipVisionRange();
	long lookX, lookY;
	
	if ((abs(relativeX) > visionRange) || (abs(relativeY) > visionRange))	// a request has been made to look further than the available visual range
	{ return false; }														// always return false... nothing is seen!
	
	else
	{
		// convert the ship-relative coordinates to grid coorindates
		// allowing for any run-around of the torus world edges in the sea
		lookX = seaPtr->wrapAroundIndexByDimension(getShipPositionX() + relativeX);
		lookY = seaPtr->wrapAroundIndexByDimension(getShipPositionY() + relativeY);
		
		return seaPtr->cellArrayIsOccupiedByShip(lookX, lookY);
	}
	
	return false; // silence compiler warning
}

bool AIController::isRockAt(long relativeX, long relativeY)
const
{
	assert(seaPtr);
	long visionRange = getShipVisionRange();
	long lookX, lookY;
	
	if ((abs(relativeX) > visionRange) || (abs(relativeY) > visionRange))	// a request has been made to look further than the available visual range
	{ return false; }														// always return false... nothing is seen!
	
	else
	{
		// convert the ship-relative coordinates to grid coorindates
		// allowing for any run-around of the torus world edges in the sea
		lookX = seaPtr->wrapAroundIndexByDimension(getShipPositionX() + relativeX);
		lookY = seaPtr->wrapAroundIndexByDimension(getShipPositionY() + relativeY);
		
		return seaPtr->cellArrayIsOccupiedByRock(lookX, lookY);
	}
	
	return false; // silence compiler warning
}

// *NB this method computes the next action the ship wants to perform
// but it does not change the ship's state. The ship's request for this
// action will be assessed by the framework and success or failure will be returned.

Globals::ShipAction AIController::computeNextAction(void)
{
	Globals::ShipAction action = Globals::actionPass;
	long randNum = (random() % 6);
	
	// then work out what action we want to do next
	switch (randNum)
	{
		case 0:
			action = Globals::actionTurnLeft;
		break;
		case 1:
			action = Globals::actionTurnRight;
		break;
		case 2:
			action = Globals::actionMoveAhead;
		break;
		case 3:
			action = Globals::actionCollectGold;
		break;
		case 4:
			action = Globals::actionFireCannonAhead;
		break;
		case 5:
			action = Globals::actionPass;
		break;
		default:
			std::cerr << "ERROR: AIController::computeNextAction() selected invalid action!";
	}
	return action;
}

